"""
 +----------------------------------------------------------------------+   
 |  Copyright (C) 2008 crodas,czayas                                    |      
 |                                                                      |
 |  Except where otherwise indicated,                                   |
 |  this program is free software; you can redistribute it and/or       |
 |  modify it under the terms of the GNU General Public License         |
 |  as published by the Free Software Foundation; either version 2      |
 |  of the License, or (at your option) any later version.              |
 |                                                                      |
 |  This program is distributed in the hope that it will be useful,     |
 |  but WITHOUT ANY WARRANTY; without even the implied warranty of      |
 |  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the       |
 |  GNU General Public License for more details.                        |
 |                                                                      |
 |  You should have received a copy of the GNU General Public License   |
 |  along with this program; if not, write to the Free Software         |
 |  Foundation, Inc., 59 Temple Place - Suite 330,                      |
 |  Boston, MA  02111-1307, USA.                                        |
 +----------------------------------------------------------------------+
 |  Authors:                                                            |
 |      Carlos Zayas <czayas@etopapy.org>                               |
 |      Cesar Rodas <crodas@etopapy.org>                                |
 +----------------------------------------------------------------------+
 |  File Crawler                                                        |
 |                                                                      |
 |  This module scans files and updates the database.                   |
 |                                                                      |
 +----------------------------------------------------------------------+
"""
import os
import dbm
import osl


acc=0
def handler( files ):
    """ 
        This function is used as a file processing. It is the easiest way
        to process all files, because saving all the path on the main memory
        is a bad idea ;)
    """
    global acc
    acc += len(files)
    print acc
    
    db = dbm.open("database.sdb")
    cu = db.cursor()
    cu.execute("begin") 
    for file in files:
        """
            Search and get the directory ID, if it doesn't exists, insert this 
            directory
        """
        r = cu.execute('select dirid from directories where directory = :dir', {'dir':file['dir']}).fetchall()
        if r == []:
            cu.execute("insert into directories(directory) values(:dir)", {'dir':file['dir']})
            r = cu.execute('select last_insert_rowid() ').fetchall()
        
        """ 
            Insert the new file, try except are used to avoid duplication of data, because
            it is easiest and cheapest for SQLite to control this than SQLite + Python.
        """
        try:
            cu.execute("insert into files values(:dir, :path)", {'dir':r[0][0],'path':file['name'] } )
        except:pass
        
    cu.execute("commit")
    db.close()

    
def gatherfiles(fnc_processing,max,filesroot):
        """ 
            Gather a complete list of files of the whole file system, when the number
            of files is greater than MAX, we call the fnc_processing, then release memory
            for a better perfomance.
        """
        gath_files = []
 
        for froot in filesroot:
            for root, dirs, files in os.walk( froot ): 
                for name in files:
                    if len(gath_files) > max:
                        fnc_processing(gath_files  )
                        del gath_files
                        gath_files  = []
                    """
                        To solve problem found with:
                            select * from tindex where path not like '?:\\%'   limit 10
                        It index whole path and file name.
                    """
                    gath_files.append( {'name':name, 'dir':root} )


def opendb():
    """ Open and Init the database """
    db = dbm.open("database.sdb")
    if not db:
        raise Exception("Couldn't open main database")
    try:
        cur = db.cursor()
        cur.execute("begin")
        cur.execute("""CREATE TABLE [directories] (
        [dirid] INTEGER  NOT NULL PRIMARY KEY AUTOINCREMENT,
        [directory] VARCHAR(250)  UNIQUE NOT NULL
        );""") 
        cur.execute("""CREATE TABLE [files] (
        [dir] INTEGER  NOT NULL,
        [file] VARCHAR(50)  NOT NULL
        );""")
        cur.execute("""CREATE INDEX [IDX_DIRECTORIES_DIRECTORY] ON [directories](
        [directory]  ASC
        );""")
        cur.execute("""CREATE UNIQUE INDEX [unique_file] ON [files](
        [dir]  ASC,
        [file]  ASC
        );""")
        cur.execute("""CREATE INDEX [IDX_FILES_DIR] ON [files](
        [dir]  ASC
        );""")
        cur.execute("""CREATE INDEX [IDX_FILES_FILE] ON [files](
        [file]  ASC
        );""")

        cur.execute("commit")
    except:
        pass
    db.close()
        

def index():
    """ Create the files index """
    fos = osl.getoslayer()
    opendb()
    gatherfiles( handler, 1000,  fos.getfilespath() )


def search( item ):
    """
        Searches the database for the string passed as a parameter (item).
    """
    db = dbm.open("database.sdb")
    cu = db.cursor()
    cu.execute("begin")

    # First, it searches the files table.
    r = cu.execute('select dir, file from files where file like :item', {"item":item}).fetchall()
    if r == []:
        # Then, it searches the directories table.
        r = cu.execute('select directory from directories where directory like :item', {"item":item}).fetchall()

    """
        To do:

        - SQL's "LIKE" is not enough, specially when it comes to search directories.
          How can we search inside string fields in SQL? Maybe with regular expressions?

        - Directory matches should be added to file matches, and differentiated somehow.
          Or maybe is better something like:
              def search( item, type ) # where type = "D" or "F" ?
    """

    return r
